package com.fubowen.lepton.components

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.widget.ScrollView
import com.fubowen.lepton.R
import kotlin.math.abs

class ClickableScrollView(
    context: Context,
    attrs: AttributeSet?
) : ScrollView(context, attrs) {

    private var region = 0x00
    private var bound = 30f
    private var bg = 0
    private var hint: String? = null
    private var hintSize = 24f
    private var radius = 0f

    private var downX = 0f
    private var downY = 0f
    private val rectPaint = Paint()
    private val textPaint = Paint()

    private var isInRegionOfClick = false
    val inRegionOfClick get() = isInRegionOfClick
    private var isDrawClickRegion = false
        set(value) {
            field = value
            if (value) invalidate()
        }

    init {
        val typed = context.obtainStyledAttributes(attrs, R.styleable.ClickableScrollView)
        region = typed.getInt(R.styleable.ClickableScrollView_click_region, region)
        bound = typed.getDimension(R.styleable.ClickableScrollView_click_and_slide_bound, bound)
        bg = typed.getColor(R.styleable.ClickableScrollView_click_region_background, bg)
        hint = typed.getString(R.styleable.ClickableScrollView_click_region_hint)
        hintSize = typed.getDimension(
            R.styleable.ClickableScrollView_click_region_hint_size,
            spToPx(hintSize)
        )
        radius = typed.getDimension(R.styleable.ClickableScrollView_click_region_radius, radius)
    }

    private fun getClickRegionList(startOffsetY: Int): ArrayList<RectF> {
        val rectList = ArrayList<RectF>()
        var t = startOffsetY + paddingTop
        var b = startOffsetY + height - paddingBottom
        val l = paddingLeft
        val r = width - paddingRight

        //region 相对于可视区
        if (region and CONTENT == CONTENT) {
            rectList.add(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()))
        }

        if (region and TOP == TOP) {
            b = t + height / 3
            rectList.add(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()))
        }
        if (region and TOP == TOP) {
            b = t + height / 3
            rectList.add(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()))
        }

        if (region and MIDDLE == MIDDLE) {
            t += height / 3
            b = t + height / 3
            rectList.add(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()))
        }

        if (region and BOTTOM == BOTTOM) {
            t += height / 3 * 2
            b = t + height / 3
            rectList.add(RectF(l.toFloat(), t.toFloat(), r.toFloat(), b.toFloat()))
        }

        //endregion

        return rectList
    }

    private fun inRegionOfClick(ev: MotionEvent): Boolean {
        if (region == 0) {
            return true
        }
        val rectList = getClickRegionList(0)
        return rectList.any { it.contains(ev.x, ev.y) }
    }

    private fun spToPx(sp: Float) =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, resources.displayMetrics)

    private fun drawClickRegion(canvas: Canvas) {
        val rectList = getClickRegionList(scrollY)
        if (bg != 0) {
            rectPaint.style = Paint.Style.FILL
            rectPaint.color = bg
            for (rect in rectList) {
                canvas.drawRoundRect(rect, radius, radius, rectPaint)
            }
        }
        hint?.let {
            textPaint.style = Paint.Style.FILL
            textPaint.color = Color.WHITE
            textPaint.textSize = hintSize
            textPaint.isFakeBoldText = true

            for (rect in rectList) {
                val hintWidth = textPaint.measureText(it)
                val x = rect.centerX() - hintWidth / 2
                val y = rect.centerY()
                canvas.drawText(it, x, y, textPaint)
            }
        }
    }

    override fun dispatchDraw(canvas: Canvas) {
        super.dispatchDraw(canvas)
        if (isDrawClickRegion) drawClickRegion(canvas)
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                downX = ev.rawX
                downY = ev.rawY
            }

            MotionEvent.ACTION_UP -> {
                val diffX = abs(ev.rawX - downX)
                val diffY = abs(ev.rawY - downY)
                if (diffX <= bound && diffY <= bound) {
                    isInRegionOfClick = inRegionOfClick(ev)
                    performClick()
                }
            }
        }
        return super.onTouchEvent(ev)
    }

    companion object {
        const val TOP = 0x01
        const val MIDDLE = 0x02
        const val BOTTOM = 0x04
        const val CONTENT = 0x08
    }
}